home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CU Amiga Super CD-ROM 11
/
CU Amiga Magazine's Super CD-ROM 11 (1997)(EMAP Images)(GB)(Track 1 of 3)[!][issue 1997-06].iso
/
cucd
/
graphics
/
mpimage
/
si
/
savempi.c
< prev
next >
Wrap
C/C++ Source or Header
|
1997-03-04
|
73KB
|
3,010 lines
// MPImage - Amiga Image Conversion
// Copyright (C) © 1996 Mark John Paddock
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
// mark@topic.demon.co.uk
// mpaddock@cix.compulink.co.uk
#include "mpimage.h"
// Following explains(?) the palette choices
// 0 = x00 = b00000000
// 85 = x55 = b01010101
// 170 = xaa = b10101010
// 255 = xff = b11111111
// 0 = x00 = o000 = b00000000
// 36 = x24 = o111 = b00100100
// 73 = x49 = o222 = b01001001
// 109 = x6d = o333 = b01101101
// 146 = x92 = o444 = b10010010
// 182 = xb6 = o555 = b10110110
// 219 = xdb = o666 = b11011011
// 255 = xff = o777 = b11111111
// 0 = x00 = b00000000
// 17 = x11 = b00010001
// 34 = x22 = b00100010
// 51 = x33 = b00110011
// 68 = x44 = b01000100
// 85 = x55 = b01010101
// 102 = x66 = b01100110
// 119 = x77 = b01110111
// 136 = x88 = b10001000
// 153 = x99 = b10011001
// 170 = xaa = b10101010
// 187 = xbb = b10111011
// 204 = xcc = b11001100
// 221 = xdd = b11011101
// 238 = xee = b11101110
// 255 = xff = b11111111
// 16 grey shade palette
UBYTE BW16_Palette[16][3] = {
0,0,0,
17,17,17,
34,34,34,
51,51,51,
68,68,68,
85,85,85,
102,102,102,
119,119,119,
136,136,136,
153,153,153,
170,170,170,
187,187,187,
204,204,204,
221,221,221,
238,238,238,
255,255,255
};
// 256 grey shade palette
UBYTE BW256_Palette[256][3] = {
0,0,0,
1,1,1,
2,2,2,
3,3,3,
4,4,4,
5,5,5,
6,6,6,
7,7,7,
8,8,8,
9,9,9,
10,10,10,
11,11,11,
12,12,12,
13,13,13,
14,14,14,
15,15,15,
16,16,16,
17,17,17,
18,18,18,
19,19,19,
20,20,20,
21,21,21,
22,22,22,
23,23,23,
24,24,24,
25,25,25,
26,26,26,
27,27,27,
28,28,28,
29,29,29,
30,30,30,
31,31,31,
32,32,32,
33,33,33,
34,34,34,
35,35,35,
36,36,36,
37,37,37,
38,38,38,
39,39,39,
40,40,40,
41,41,41,
42,42,42,
43,43,43,
44,44,44,
45,45,45,
46,46,46,
47,47,47,
48,48,48,
49,49,49,
50,50,50,
51,51,51,
52,52,52,
53,53,53,
54,54,54,
55,55,55,
56,56,56,
57,57,57,
58,58,58,
59,59,59,
60,60,60,
61,61,61,
62,62,62,
63,63,63,
64,64,64,
65,65,65,
66,66,66,
67,67,67,
68,68,68,
69,69,69,
70,70,70,
71,71,71,
72,72,72,
73,73,73,
74,74,74,
75,75,75,
76,76,76,
77,77,77,
78,78,78,
79,79,79,
80,80,80,
81,81,81,
82,82,82,
83,83,83,
84,84,84,
85,85,85,
86,86,86,
87,87,87,
88,88,88,
89,89,89,
90,90,90,
91,91,91,
92,92,92,
93,93,93,
94,94,94,
95,95,95,
96,96,96,
97,97,97,
98,98,98,
99,99,99,
100,100,100,
101,101,101,
102,102,102,
103,103,103,
104,104,104,
105,105,105,
106,106,106,
107,107,107,
108,108,108,
109,109,109,
110,110,110,
111,111,111,
112,112,112,
113,113,113,
114,114,114,
115,115,115,
116,116,116,
117,117,117,
118,118,118,
119,119,119,
120,120,120,
121,121,121,
122,122,122,
123,123,123,
124,124,124,
125,125,125,
126,126,126,
127,127,127,
128,128,128,
129,129,129,
130,130,130,
131,131,131,
132,132,132,
133,133,133,
134,134,134,
135,135,135,
136,136,136,
137,137,137,
138,138,138,
139,139,139,
140,140,140,
141,141,141,
142,142,142,
143,143,143,
144,144,144,
145,145,145,
146,146,146,
147,147,147,
148,148,148,
149,149,149,
150,150,150,
151,151,151,
152,152,152,
153,153,153,
154,154,154,
155,155,155,
156,156,156,
157,157,157,
158,158,158,
159,159,159,
160,160,160,
161,161,161,
162,162,162,
163,163,163,
164,164,164,
165,165,165,
166,166,166,
167,167,167,
168,168,168,
169,169,169,
170,170,170,
171,171,171,
172,172,172,
173,173,173,
174,174,174,
175,175,175,
176,176,176,
177,177,177,
178,178,178,
179,179,179,
180,180,180,
181,181,181,
182,182,182,
183,183,183,
184,184,184,
185,185,185,
186,186,186,
187,187,187,
188,188,188,
189,189,189,
190,190,190,
191,191,191,
192,192,192,
193,193,193,
194,194,194,
195,195,195,
196,196,196,
197,197,197,
198,198,198,
199,199,199,
200,200,200,
201,201,201,
202,202,202,
203,203,203,
204,204,204,
205,205,205,
206,206,206,
207,207,207,
208,208,208,
209,209,209,
210,210,210,
211,211,211,
212,212,212,
213,213,213,
214,214,214,
215,215,215,
216,216,216,
217,217,217,
218,218,218,
219,219,219,
220,220,220,
221,221,221,
222,222,222,
223,223,223,
224,224,224,
225,225,225,
226,226,226,
227,227,227,
228,228,228,
229,229,229,
230,230,230,
231,231,231,
232,232,232,
233,233,233,
234,234,234,
235,235,235,
236,236,236,
237,237,237,
238,238,238,
239,239,239,
240,240,240,
241,241,241,
242,242,242,
243,243,243,
244,244,244,
245,245,245,
246,246,246,
247,247,247,
248,248,248,
249,249,249,
250,250,250,
251,251,251,
252,252,252,
253,253,253,
254,254,254,
255,255,255,
};
// HAM6 base palette
// note 3 extra entries based on changing r,g or b using HAM stuff
static UBYTE HAM6_Palette[19][3] = {
0,0,0,
0,0,170,
0,85,0,
0,85,170,
0,170,0,
0,170,170,
0,255,0,
0,255,170,
170,0,0,
170,0,170,
170,85,0,
170,85,170,
170,170,0,
170,170,170,
170,255,0,
255,255,255,
0,0,0, // r
0,0,0, // g
0,0,0, // b
};
// HAM8 base palette
// note 3 extra entries based on changing r,g or b using HAM stuff
UBYTE HAM8_Palette[67][3] = {
0,0,0,
0,0,170,
0,36,0,
0,36,170,
0,73,0,
0,73,170,
0,109,0,
0,109,170,
0,146,0,
0,146,170,
0,182,0,
0,182,170,
0,219,0,
0,219,170,
0,255,0,
0,255,170,
85,0,0,
85,0,170,
85,36,0,
85,36,170,
85,73,0,
85,73,170,
85,109,0,
85,109,170,
85,146,0,
85,146,170,
85,182,0,
85,182,170,
85,219,0,
85,219,170,
85,255,0,
85,255,170,
170,0,0,
170,0,170,
170,36,0,
170,36,170,
170,73,0,
170,73,170,
170,109,0,
170,109,170,
170,146,0,
170,146,170,
170,182,0,
170,182,170,
170,219,0,
170,219,170,
170,255,0,
170,255,170,
255,0,0,
255,0,170,
255,36,0,
255,36,170,
255,73,0,
255,73,170,
255,109,0,
255,109,170,
255,146,0,
255,146,170,
255,182,0,
255,182,170,
255,219,0,
255,219,170,
255,255,0,
255,255,255,
0,0,0, // r
0,0,0, // g
0,0,0, // b
};
UBYTE MyPalette[256][3];
UBYTE DefGreyMap[256] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111,
112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,
128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255
};
BOOL __asm __saveds SaveMPImageA(register __a0 const UBYTE *file,
register __a1 UBYTE *red, register __a2 UBYTE *green,register __a3 UBYTE *blue,
register __d0 UWORD width, register __d1 UWORD height,
register __a5 struct TagItem *TagList);
extern UWORD MedianCut(UWORD Hist[],UBYTE ColMap[][3], int maxcubes, UWORD HistPtr[]);
extern UWORD MedHam6(UWORD Hist[],UBYTE ColMap[][3], int maxcubes, UWORD HistPtr[]);
static ULONG LoadPalette(UBYTE *filename);
static BOOL ComputePalette(UWORD Depth,UWORD width,UWORD height,UBYTE *red,UBYTE *green,UBYTE *blue);
static BOOL ComputePal12(UWORD Depth,UWORD width,UWORD height,UBYTE *red,UBYTE *green,UBYTE *blue);
static BOOL ComputePalEHB(UWORD width,UWORD height,UBYTE *red,UBYTE *green,UBYTE *blue);
static ULONG GetMode(UWORD height, UWORD width, UWORD depth, ULONG camg, ULONG flags, const UBYTE * filename);
static BOOL SaveBW16(const UBYTE *FileName,USHORT width,USHORT height,
UBYTE *red, UBYTE *green, UBYTE *blue, UBYTE palette[][3], ULONG camg, UBYTE *GreyMap, BOOL Linear, struct BitMap *NewBitMap);
static BOOL SaveBW256(const UBYTE *FileName,USHORT width,USHORT height,
UBYTE *red, UBYTE *green, UBYTE *blue, UBYTE palette[][3], ULONG camg, UBYTE *GreyMap, BOOL Linear, struct BitMap *NewBitMap);
static BOOL SaveHAM6(const UBYTE *FileName,USHORT width,USHORT height,
UBYTE *red, UBYTE *green, UBYTE *blue, UBYTE palette[][3], ULONG camg,struct BitMap *NewBitMap);
static BOOL SaveHAM8(const UBYTE *FileName,USHORT width,USHORT height,
UBYTE *red, UBYTE *green, UBYTE *blue, UBYTE palette[][3], ULONG camg,struct BitMap *NewBitMap);
static BOOL Save24(const UBYTE *FileName,USHORT width,USHORT height,
UBYTE *red, UBYTE *green, UBYTE *blue, ULONG camg);
static BOOL SavePPM(const UBYTE *FileName,USHORT width,USHORT height,
UBYTE *red, UBYTE *green, UBYTE *blue,UWORD jpeg);
static BOOL SaveColour(const UBYTE *FileName,USHORT width,USHORT height,
UBYTE *red, UBYTE *green, UBYTE *blue, ULONG camg, ULONG numcols,struct BitMap *NewBitMap);
static BOOL SaveColour12(const UBYTE *FileName,USHORT width,USHORT height,
UBYTE *red, UBYTE *green, UBYTE *blue, ULONG camg, ULONG numcols,struct BitMap *NewBitMap);
static BOOL SaveEHB(const UBYTE *FileName,USHORT width,USHORT height,
UBYTE *red, UBYTE *green, UBYTE *blue, ULONG camg,struct BitMap *NewBitMap);
static BOOL SaveDCTV(const UBYTE *FileName,USHORT width,USHORT height,
UBYTE *red, UBYTE *green, UBYTE *blue, ULONG camg,BOOL dctv4,struct BitMap *NewBitMap);
static LONG mysaveilbm(struct ILBMInfo *ilbm,
struct BitMap *bitmap, ULONG modeid,
WORD width, WORD height, WORD pagewidth, WORD pageheight,
UBYTE colortable[][3], UWORD count, UWORD bitspergun,
WORD masking, WORD transparentColor,
struct Chunk *chunklist1, struct Chunk *chunklist2,
UBYTE *filename,int Depth);
// Properties for IFF read
static LONG props[] = { ID_ILBM, ID_BMHD,
ID_ILBM, ID_CAMG,
ID_ILBM, ID_CMAP,
TAG_DONE };
static LONG stops[] = { ID_ILBM, ID_BODY,
TAG_DONE };
static LONG nowt[] = { TAG_DONE };
static void
CopyNewPal(UBYTE OldPal[][3],UBYTE *NewPal,ULONG Cols) {
int i;
for (i=0; i<Cols; ++i) {
NewPal[i] = OldPal[i][0];
NewPal[i+256] = OldPal[i][1];
NewPal[i+512] = OldPal[i][2];
}
}
static void
CopyOldPal(UBYTE *NewPal,UBYTE OldPal[][3],ULONG Cols) {
int i;
for (i=0; i<Cols; ++i) {
OldPal[i][0] = NewPal[i];
OldPal[i][1] = NewPal[i+256];
OldPal[i][2] = NewPal[i+512];
}
}
/****** MPImage.library/SaveMPImageA *****************************************
*
* NAME
* SaveMPImageA -- Save an image in various formats. (V3)
* SaveMPIMage -- Varargs version of SaveMPImageA (V3)
*
* SYNOPSIS
* succ = SaveMPImageA( file,red,green,blue,width,height,taglist)
* D0 A0 A1 A2 A3 D0 D1 A5
*
* BOOL SaveMPImageA( UBYTE *,UBYTE *,UBYTE *,UBYTE *,
* UWORD,UWORD,struct TagItem *);
*
* succ = SaveMPImage( file,red,green,blue,width,height,Tag1, ...)
*
* BOOL SaveMPImage( UBYTE *,UBYTE *,UBYTE *,UBYTE *,
* UWORD,UWORD,ULONG,...);
*
* FUNCTION
* Saves/displays an image held in chunky buffers.
*
* INPUTS
* file - filename to save file as. If NULL or "" then image is
* displayed on a custom screen, or returned in BitMap (V7.0)
* red - red chunky input.
* green - green chunky input.
* blue - blue chunky input.
* width - width of chunky buffers
* height - height of chunky buffers.
* taglist - pointer to TagItem array.
*
* Tags are:
*
* MPIS_MODE - Data is ULONG CAMG of output IFF file/screen EHB and HAM
* will be added if required. If not supplied then
* MPIS_MODENAME will be used. If that is not supplied then
* a CAMG mode will be generated.
* MPIS_MODENAME - Data is char * mode name of CAMG of output. Invalid
* names are ignored.
* MPIS_FORMAT - Data is char * specifying output format.
* Default is MPI_BW16. Values are:
* MPI_BW16 - "BW16" - 16 colour ILBM grey scale.
* MPI_BW256 - "BW256" - 256 colour ILBM grey scale.
* MPI_HAM6 - "HAM6" - HAM6 with fixed (internal) palette.
* MPI_HAM6P - "HAM6P" - HAM6 with generated or supplied
* palette - see MPIS_PALETTE.
* MPI_HAM8 - "HAM8" - HAM8 with fixed (internal) palette.
* MPI_HAM8P - "HAM8P" - HAM8 with generated or supplied
* palette - see MPIS_PALETTE.
* MPI_ILBM24 - "ILBM24" - 24 bit ILBM.
* MPI_PPM - "PPM" - P6 (or P5 if red,green and blue are
* the same).
* MPI_COLOUR - "COLOUR" - ILBM with generated or supplied
* palette - see MPIS_PALETTE.
* MPI_EHB - "EHB" - EHB with generated or supplied
* palette - see MPIS_PALETTE.
* MPI_JPEG - "JPEG" - JPEG see NOTES.
* MPI_PNM - "PNG" - PNG see NOTES.
* MPI_DCTV3 - "DCTV3" - DCTV 3 bit plane format
* MPI_DCTV4 - "DCTV4" - DCTV 4 bit plane format
* MPIS_PALETTE - Data is char * name of ILBM to load palette from.
* MPIS_COLOURS - Data is ULONG number of colours for MPI_COLOUR.
* Default is is number of colours in MPIS_PALETTE if
* supplied, otherwise 16. If greater than that from
* MPIS_PALETTE then ignored.
* MPIS_12BIT - Data is BOOL. If TRUE then use faster 12bit colour palette
* generating algorithm for MPI_COLOUR and MPI_EHB. Default
* is FALSE to use 18bit algorithm.
* MPIS_LINEAR - Data is BOOL. If TRUE then for BW16/BW256 use linear
* (not colour based) mapping. (V5.0)
* MPIS_GREYMAP - Data is UBYTE *. For BW16/BW256 palette map. Must point
* to at least 16 of value 0 to 15 for BW16, 256 bytes of
* 0 to 255 for BW255. (V5.0)
* Format is e.g. 0,2,3,4,5,6,7,8,9,10,11,12,13,14,15,1
* Colour 0 will be black
* Colour 1 will be white
* etc.
* This is the opposite to which you may expect!
* MPIS_OLDPALETTE - Palette to use (for HAMxP/COLOUR/EHB) (V7.0)
* Data is UBYTE *, red in [0] to [255],
* green in [256] to [511]
* blue in [512] to [767]
* MPIS_NEWPALETTE - Palette used (for HAMx/COLOUR/EHB) (V7.0)
* Data is UBYTE * (see MPIS_OLDPALETTE).
* MPIS_BITMAP - BitMap to update (for BWxx/HAMxx/COLOUR/EHB/DCTVx) (V7.0)
* Data is struct BitMap *
* Image is not displayed/saved
*
* RESULT
* error - 1 for success, 0 for failure.
* Use MPImageErrorMessage() to get error.
*
* EXAMPLE
*
* NOTES
* If MPIS_FORMAT is BW16 or BW256 and red,green and blue are the same then
* a more efficent algorithm is used.
*
* When displaying on screen click in the top left and press a key to exit.
*
* If file format is JPEG and env/mpimage/cjpeg is set (e.g. cjpeg "%s" "%s")
* then cjpeg is used.
*
* If file format is PNG and env/mpimage/pnmtopng is set
* (e.g. 'pnmtopng "%s" >"%s"') then pnmtopng is used.
*
* BUGS
* Does not work for images > 1024 wide (except PPM/JPEG/PNG).
* The palette file requires a body which is loaded and then discarded.
*
* Waits 20 seconds for cjpeg/pnmtopng to start then aborts. This check is
* not fool proof and the PIPE:xxx can be left hanging.
*
* Prior to version 4.3 fails to determine a screen mode correctly.
*
* V7.0 did not handle MPIS_BITMAP correctly.
*
* V7.3 did not set return code when MPIS_BITMAP supplied.
*
* SEE ALSO
* MPImageErrorMessage().
*
*****************************************************************************
*
*/
BOOL __asm __saveds
SaveMPImageA(register __a0 const UBYTE *file,
register __a1 UBYTE *red, register __a2 UBYTE *green,register __a3 UBYTE *blue,
register __d0 UWORD width, register __d1 UWORD height,
register __a5 struct TagItem *TagList) {
struct TagItem *ti;
ULONG camg = (ULONG)INVALID_ID;
UBYTE *format = NULL;
UBYTE *palette = NULL;
ULONG numcols = 0;
ULONG numcols1;
BOOL bit12 = FALSE;
char *modename;
ULONG id = (ULONG)INVALID_ID;
struct NameInfo buff;
BOOL ret;
BOOL Linear = FALSE;
UBYTE *GreyMap = NULL;
UBYTE *OldPal = NULL;
UBYTE *NewPal = NULL;
struct BitMap *RetBitMap = NULL;
if (ti = FindTagItem(MPIS_OLDPALETTE,TagList)) {
OldPal = (UBYTE *)ti->ti_Data;
}
if (ti = FindTagItem(MPIS_NEWPALETTE,TagList)) {
NewPal = (UBYTE *)ti->ti_Data;
}
if (ti = FindTagItem(MPIS_BITMAP,TagList)) {
RetBitMap = (struct BitMap *)ti->ti_Data;
}
if (ti = FindTagItem(MPIS_MODE,TagList)) {
camg = ti->ti_Data;
}
else {
if (ti = FindTagItem(MPIS_MODENAME,TagList)) {
modename = (char *)(ti->ti_Data);
if (modename && *modename) {
id = NextDisplayInfo(id);
while ((id != INVALID_ID) && (camg == INVALID_ID)) {
if (GetDisplayInfoData(NULL,(UBYTE *)&buff,sizeof(struct NameInfo),DTAG_NAME,id)) {
if (!Stricmp(buff.Name,modename)) {
camg = id;
}
}
id = NextDisplayInfo(id);
}
}
}
}
if (ti = FindTagItem(MPIS_FORMAT,TagList)) {
format = (UBYTE *)(ti->ti_Data);
}
if (!format) {
format = MPI_BW16;
}
if (ti = FindTagItem(MPIS_COLOURS,TagList)) {
numcols = ti->ti_Data;
}
if (ti = FindTagItem(MPIS_12BIT,TagList)) {
bit12 = ti->ti_Data;
}
if (ti = FindTagItem(MPIS_LINEAR,TagList)) {
Linear = ti->ti_Data;
}
if (ti = FindTagItem(MPIS_GREYMAP,TagList)) {
GreyMap = (UBYTE *)(ti->ti_Data);
}
if (ti = FindTagItem(MPIS_PALETTE,TagList)) {
palette = (UBYTE *)(ti->ti_Data);
}
if (palette) {
if (!(numcols1 = LoadPalette(palette))) {
return FALSE;
}
if (numcols > numcols1) {
numcols = numcols1;
}
}
if (numcols > 256) {
numcols = 256;
}
if (!numcols) {
numcols = 16;
}
if (numcols < 2) {
numcols = 2;
}
if (!SetupScreen()) {
OpenProgressWindow();
}
if (!Stricmp(format,MPI_BW16)) {
if (GreyMap) {
int i;
for (i = 0; i < 16; ++i) {
MyPalette[GreyMap[i]][0]=i + (i<<4);
MyPalette[GreyMap[i]][1]=i + (i<<4);
MyPalette[GreyMap[i]][2]=i + (i<<4);
}
ret = SaveBW16(file,width,height, red, green, blue, MyPalette, camg, GreyMap, Linear, RetBitMap);
}
else {
ret = SaveBW16(file,width,height, red, green, blue, BW16_Palette, camg, DefGreyMap, Linear, RetBitMap);
}
}
else if (!Stricmp(format,MPI_BW256)) {
if (GreyMap) {
int i;
for (i = 0; i < 256; ++i) {
MyPalette[GreyMap[i]][0]=i;
MyPalette[GreyMap[i]][1]=i;
MyPalette[GreyMap[i]][2]=i;
}
ret = SaveBW256(file,width,height, red, green, blue, MyPalette, camg, GreyMap, Linear, RetBitMap);
}
else {
ret = SaveBW256(file,width,height, red, green, blue, BW256_Palette, camg, DefGreyMap, Linear, RetBitMap);
}
}
else if (!Stricmp(format,MPI_HAM6)) {
ret = SaveHAM6(file,width,height, red, green, blue, HAM6_Palette, camg, RetBitMap);
if (NewPal) {
CopyNewPal(HAM6_Palette,NewPal,16);
}
}
else if (!Stricmp(format,MPI_HAM8)) {
ret = SaveHAM8(file,width,height, red, green, blue, HAM8_Palette, camg, RetBitMap);
if (NewPal) {
CopyNewPal(HAM8_Palette,NewPal,64);
}
}
else if (!Stricmp(format,MPI_ILBM24)) {
ret = Save24(file,width,height, red, green, blue, camg);
}
else if (!Stricmp(format,MPI_PPM)) {
ret = SavePPM(file,width,height, red, green, blue, 0);
}
else if (!Stricmp(format,MPI_HAM6P)) {
if (OldPal || palette || ComputePal12(16,width,height,red,green,blue)) {
if (OldPal) {
CopyOldPal(OldPal,MyPalette,16);
}
ret = SaveHAM6(file,width,height, red, green, blue, MyPalette, camg, RetBitMap);
if (NewPal) {
CopyNewPal(MyPalette,NewPal,16);
}
}
else {
ret = FALSE;
}
}
else if (!Stricmp(format,MPI_HAM8P)) {
if (OldPal || palette || ComputePalette(64,width,height,red,green,blue)) {
if (OldPal) {
CopyOldPal(OldPal,MyPalette,64);
}
ret = SaveHAM8(file,width,height, red, green, blue, MyPalette, camg, RetBitMap);
if (NewPal) {
CopyNewPal(MyPalette,NewPal,64);
}
}
else {
ret = FALSE;
}
}
else if (!Stricmp(format,MPI_COLOUR) && !bit12) {
if (OldPal || palette || ComputePalette(numcols,width,height,red,green,blue)) {
if (OldPal) {
CopyOldPal(OldPal,MyPalette,numcols);
}
ret = SaveColour(file,width,height, red, green, blue, camg, numcols,RetBitMap);
if (NewPal) {
CopyNewPal(MyPalette,NewPal,numcols);
}
}
else {
ret = FALSE;
}
}
else if (!Stricmp(format,MPI_COLOUR) && bit12) {
if (OldPal || palette || ComputePal12(numcols,width,height,red,green,blue)) {
if (OldPal) {
CopyOldPal(OldPal,MyPalette,numcols);
}
ret = SaveColour12(file,width,height, red, green, blue, camg, numcols, RetBitMap);
if (NewPal) {
CopyNewPal(MyPalette,NewPal,numcols);
}
}
else {
ret = FALSE;
}
}
else if (!Stricmp(format,MPI_EHB)) {
if (OldPal) {
CopyOldPal(OldPal,MyPalette,32);
}
if (OldPal || palette || ComputePalEHB(width,height,red,green,blue)) {
ret = SaveEHB(file,width,height, red, green, blue, camg, RetBitMap);
if (NewPal) {
CopyNewPal(MyPalette,NewPal,64);
}
}
else {
ret = FALSE;
}
}
else if (!Stricmp(format,MPI_JPEG)) {
ret = SavePPM(file,width,height, red, green, blue, 1);
}
else if (!Stricmp(format,MPI_PNG)) {
ret = SavePPM(file,width,height, red, green, blue, 2);
}
else if (!Stricmp(format,MPI_DCTV3)) {
ret = SaveDCTV(file,width,height, red, green, blue, camg, FALSE, RetBitMap);
}
else if (!Stricmp(format,MPI_DCTV4)) {
ret = SaveDCTV(file,width,height, red, green, blue, camg, TRUE, RetBitMap);
}
else {
sprintf(ErrorMessage,GetMg(MSG_ERR_INVF),format);
ret = FALSE;
}
CloseProgressWindow();
CloseDownScreen();
return ret;
}
// returns 0 for error - message already set up
// otherwise returns number of colours in palette
static ULONG
LoadPalette(UBYTE *filename) {
struct ILBMInfo ilbm = {0}; // ILBM stuff
int i;
ULONG numcols;
AddMessageNo(MSG_LOADP);
if (ilbm.ParseInfo.iff = AllocIFF()) {
ilbm.ParseInfo.propchks = props;
ilbm.ParseInfo.collectchks = nowt;
ilbm.ParseInfo.stopchks = stops;
if (loadbrush(&ilbm,(char *)filename)) {
closeifile(&(ilbm.ParseInfo));
unloadbrush(&ilbm);
FreeIFF(ilbm.ParseInfo.iff);
return 0;
}
closeifile(&(ilbm.ParseInfo));
numcols = ilbm.ncolors;
AddMessageNo(MSG_GETC);
for (i=0; i < numcols; ++i) {
MyPalette[i][0]=(ilbm.colortable32[i].r)>>24;
MyPalette[i][1]=(ilbm.colortable32[i].g)>>24;
MyPalette[i][2]=(ilbm.colortable32[i].b)>>24;
}
unloadbrush(&ilbm);
FreeIFF(ilbm.ParseInfo.iff);
return numcols;
}
else {
strcpy(ErrorMessage,GetMg(MSG_ERR_IFF));
return 0;
}
}
#define HSIZE 32768 /* size of image histogram */
/* Macros for converting between (r,g,b)-colors and 15-bit */
/* colors follow. */
#define RGB(r,g,b) (UWORD)(((b)&~7)<<7)|(((g)&~7)<<2)|((r)>>3)
static BOOL
ComputePalette(UWORD Depth,UWORD width,UWORD height,UBYTE *red,UBYTE *green,UBYTE *blue) {
UWORD *hist;
UBYTE *r=red,*g=green,*b=blue;
int i,j;
if (hist = AllocVec(sizeof(UWORD)*HSIZE*2,MEMF_CLEAR)) {
AddMessageNo(MSG_HIST);
SetMax(height);
memset(MyPalette,0,256*3);
for (i = 0; i < height; ++i) {
SetCur(i);
for (j = 0; j < width; ++j) {
hist[RGB(*r++,*g++,*b++)] += 1;
}
}
AddMessageNo(MSG_CPAL);
MedianCut(hist,MyPalette,Depth,&(hist[HSIZE]));
FreeVec(hist);
return TRUE;
}
else {
strcpy(ErrorMessage,GetMg(MSG_ERR_NOMEM));
return FALSE;
}
}
#define HSIZE6 4096 /* size of image histogram */
/* Macros for converting between (r,g,b)-colors and 12-bit */
/* colors follow. */
#define RGB6(r,g,b) (UWORD)((((b)&~15)<<4)|((g)&~15)|((r)>>4))
#define RED6(x) ((((x)&15)<<4)|((x)&15))
#define GREEN6(x) (((((x)>>4)&15)<<4)|((((x)>>4)&15)))
#define BLUE6(x) (((((x)>>8)&15)<<4)|((((x)>>8)&15)))
static BOOL
ComputePal12(UWORD Depth, UWORD width,UWORD height,UBYTE *red,UBYTE *green,UBYTE *blue) {
UWORD *hist;
UBYTE *r=red,*g=green,*b=blue;
int i,j;
if (hist = AllocVec(sizeof(UWORD)*HSIZE6*2,MEMF_CLEAR)) {
AddMessageNo(MSG_HIST);
SetMax(height);
memset(MyPalette,0,256*3);
for (i = 0; i < height; ++i) {
SetCur(i);
for (j = 0; j < width; ++j) {
hist[RGB6(*r++,*g++,*b++)] += 1;
}
}
AddMessageNo(MSG_CPAL);
MedHam6(hist,MyPalette,Depth,&(hist[HSIZE6]));
FreeVec(hist);
return TRUE;
}
else {
strcpy(ErrorMessage,GetMg(MSG_ERR_NOMEM));
return FALSE;
}
}
static BOOL
ComputePalEHB(UWORD width,UWORD height,UBYTE *red,UBYTE *green,UBYTE *blue) {
UWORD *hist;
UBYTE *r=red,*g=green,*b=blue;
int i,j,k=0;
long maxdiff,diff,t;
if (hist = AllocVec(sizeof(UWORD)*HSIZE6*4,MEMF_CLEAR)) {
AddMessageNo(MSG_HIST);
memset(MyPalette,0,256*3);
for (i = 0; i < height; ++i) {
for (j = 0; j < width; ++j) {
if ((*r > 127) || (*g > 127) || (*b > 127)) {
hist[RGB6(*r++,*g++,*b++)] += 1;
}
else {
hist[RGB6(*r++,*g++,*b++)+(HSIZE6*2)] += 1;
}
}
}
// Compute top 32 colours and bottom 32 colours
AddMessageNo(MSG_CHPAL);
MedHam6(hist,MyPalette,32,&(hist[HSIZE6]));
AddMessageNo(MSG_CLPAL);
MedHam6(&(hist[HSIZE6*2]),(UBYTE (*)[3])&(MyPalette[32][0]),32,&(hist[HSIZE6*3]));
AddMessageNo(MSG_MPAL);
for (i = 0; i < 32; i++) {
maxdiff = 0x7fffffff;
for (j = 32; (j < 64) && maxdiff; ++j) {
t = (int)MyPalette[i][0] - ((int)MyPalette[j][0]*2);
diff = t*t * 2;
if (diff < maxdiff) {
t = (int)MyPalette[i][1] - ((int)MyPalette[j][1]*2);
diff += t*t * 4;
if (diff < maxdiff) {
t = (int)MyPalette[i][2] - ((int)MyPalette[j][2]*2);
diff += t*t;
if (diff < maxdiff) {
maxdiff = diff;
k = j;
}
}
}
}
for (j = 0; j < 3; ++j) {
t = (MyPalette[i][j] + (MyPalette[k][j]*2)) / 2;
if (t > 255) {
MyPalette[i][k] = 255;
}
else {
MyPalette[i][k] = t;
}
}
}
FreeVec(hist);
return TRUE;
}
else {
strcpy(ErrorMessage,GetMg(MSG_ERR_NOMEM));
return FALSE;
}
}
// Hack a sort of modeid (caller must merge in HAM itself...)
static ULONG
GetMode(UWORD height, UWORD width,UWORD depth, ULONG camg, ULONG flags, const UBYTE *filename) {
ULONG mode=0;
if (camg != INVALID_ID) {
return camg;
}
AddMessageNo(MSG_CAMG);
// if (((ULONG)filename < 61) || !filename || !*filename) { 7.4 remove filename hack
if (!filename || !*filename) {
camg = BestModeID(BIDTAG_DIPFMustHave, flags,
BIDTAG_DIPFMustNotHave, SPECIAL_FLAGS & (~flags),
BIDTAG_NominalWidth, width,
BIDTAG_NominalHeight, height,
BIDTAG_Depth, depth,
TAG_END);
if (camg != INVALID_ID) {
return camg;
}
}
if (depth == 24) { // 24 bit so can set both hires and lace
if (width > 400) { // more than lores overscan
mode |= HIRES;
}
if (height > 300) { // more than nolace overscan
mode |= LACE;
}
}
else {
if (depth > 6) { // Must be AGA only so can have hires
if (width > 400) { // more than lores overscan
mode |= HIRES;
}
if (height > 300) { // more than nolace overscan
mode |= LACE;
}
}
else {
if (depth > 4) { // May be HAM6 or 32 colour or EHB - don't set HIRES for non-AGA
if (height > 300) {
mode |= LACE;
}
}
else { // 16 or less colours
if (width > 400) { // more than lores overscan
mode |= HIRES;
}
if (height > 300) { // more than nolace overscan
mode |= LACE;
}
}
}
}
if (flags & DIPF_IS_HAM) {
return (mode | HAM);
}
if (flags & DIPF_IS_EXTRAHALFBRITE) {
return (mode | EXTRA_HALFBRITE);
}
return mode;
}
/* save 16 grey scale
* FileName : file to save
* width : width of image
* height : height of image
* red : red
* green : green
* blue : blue chunky bit map
*/
static BOOL
SaveBW16(const UBYTE *FileName,USHORT width,USHORT height,
UBYTE *red, UBYTE *green, UBYTE *blue, UBYTE palette[][3], ULONG camg, UBYTE *GreyMap, BOOL Linear,
struct BitMap *NewBitMap) {
UBYTE *r,*g,*b;
UBYTE *old;
UWORD x,y;
BOOL OkFlag=FALSE;
struct ILBMInfo ilbm = {0};
struct MyBitMap *bitmap;
struct c2pStruct c2p;
int *word,*w;
int diff,cur,new,car;
AddMessageNo(MSG_SBW16);
bitmap = (struct MyBitMap *)NewBitMap;
// allocate IFF stuff
if ((word = AllocVec((sizeof(int))*(width+1),MEMF_CLEAR)) &&
((NewBitMap) || (bitmap = MyAllocBitMap(width,height,4,FileName)))) {
if (ilbm.ParseInfo.iff = AllocIFF()) {
if ((red == green) && (red == blue)) { // grey scale input
r = red;
old = red;
// for each line
AddMessageNo(MSG_INGREY);
SetMax(height);
for (y=0;
y<height;
y++) {
SetCur(y);
w = word; // Carrys from previous row
diff = 0; // Carry from last column
car = *w; // Carry from last row
// for each column
for (x=0;
x < width;
x++) {
// convert rgb to 16 grey scale
cur = *r++ + diff + car;
new = cur / 17;
if (new > 15) {
*old++ = GreyMap[15];
diff = cur - 15;
}
else {
if (new < 0) {
*old++ = GreyMap[0];
diff = cur;
}
else {
*old++ = GreyMap[new];
diff = cur - (new * 17);
}
}
*w++ = (diff * 3)/8; // 3/8 to pixel below
car = *w; // carry to next pixel
*w = diff / 4; // 2/8 to pixel below right
diff = (diff * 3)/8; // 3/8 to pixel right;
}
}
}
else { // not greyscale input
r = red;
g = green;
b = blue;
old = red;
AddMessageNo(MSG_INCOL);
if (Linear) {
AddMessageNo(MSG_LINEAR);
}
SetMax(height);
// for each line
for (y=0;
y<height;
y++) {
SetCur(y);
w = word; // Carrys from previous row
diff = 0; // Carry from last column
car = *w; // Carry from last row
// for each column
if (Linear) {
for (x=0;
x < width;
x++) {
// convert rgb to 16 grey scale
cur = ((int)*r++ + (int)*g++ + (int)*b++)/3 + diff + car;
new = cur / 17;
if (new > 15) {
*old++ = GreyMap[15];
diff = cur - 15;
}
else {
if (new < 0) {
*old++ = GreyMap[0];
diff = cur;
}
else {
*old++ = GreyMap[new];
diff = cur - (new * 17);
}
}
*w++ = (diff * 3)/8; // 3/8 to pixel below
car = *w; // carry to next pixel
*w = diff / 4; // 2/8 to pixel below right
diff = (diff * 3)/8; // 3/8 to pixel right;
}
}
else {
for (x=0;
x < width;
x++) {
// convert rgb to 16 grey scale
cur = (30 * (int)*r++) + (59 * (int)*g++) + (11 * (int)*b++) + diff + car + 100;
new = cur / 1700;
if (new > 15) {
*old++ = GreyMap[15];
diff = cur - (15 * 1700);
}
else {
if (new < 0) {
*old++ = GreyMap[0];
diff = cur;
}
else {
*old++ = GreyMap[new];
diff = cur - (new * 1700);
}
}
*w++ = (diff * 3)/8; // 3/8 to pixel below
car = *w; // carry to next pixel
*w = diff / 4; // 2/8 to pixel below right
diff = (diff * 3)/8; // 3/8 to pixel right;
}
}
}
}
// convert chunky to planar
c2p.bmap = (struct BitMap *)bitmap;
c2p.startX = 0;
c2p.startY = 0;
c2p.width = width;
c2p.height = height;
c2p.chunkybuffer = red;
ChunkyToPlanar(&c2p);
// and save IFF
AddMessageNo(MSG_SILBM);
if (!NewBitMap) {
OkFlag = !mysaveilbm(&ilbm, (struct BitMap *)bitmap, GetMode(height,width,4,camg,0,FileName),
width, height, width, height,
palette, 16, 8, /* colortable */
mskNone, 0, /* masking, transparent */
NULL, NULL, /* chunklisMP */
(UBYTE *)FileName,4);
}
else {
OkFlag = TRUE;
}
// Close everything down cleanly
FreeIFF(ilbm.ParseInfo.iff);
}
else {
OkFlag = FALSE;
strcpy(ErrorMessage,GetMg(MSG_ERR_IFF));
}
if (!NewBitMap) {
MyFreeBitMap(bitmap,FileName);
}
}
else {
strcpy(ErrorMessage,GetMg(MSG_ERR_ALLOCBIT));
OkFlag = FALSE;
}
if (word) {
FreeVec(word);
}
return OkFlag;
}
/* save 256 grey scale
* see SaveBW16()
*/
static BOOL
SaveBW256(const UBYTE *FileName,USHORT width,USHORT height,
UBYTE *red, UBYTE *green, UBYTE *blue, UBYTE palette[][3], ULONG camg, UBYTE *GreyMap, BOOL Linear,
struct BitMap *NewBitMap) {
UBYTE *r,*g,*b;
UBYTE *old;
UWORD x,y;
BOOL OkFlag=FALSE;
struct ILBMInfo ilbm = {0};
struct MyBitMap *bitmap;
struct c2pStruct c2p;
int *word,*w;
int diff,cur,new,car;
AddMessageNo(MSG_SBW256);
bitmap = (struct MyBitMap *)NewBitMap;
// allocate IFF stuff
if ((word = AllocVec((sizeof(int))*(width+1),MEMF_CLEAR)) &&
((NewBitMap) || (bitmap = MyAllocBitMap(width,height,8,FileName)))) {
if (ilbm.ParseInfo.iff = AllocIFF()) {
if ((red == green) && (red == blue)) { // grey scale input
r = red;
old = red;
AddMessageNo(MSG_INGREY);
SetMax(height);
for (y=0;
y<height;
y++) {
SetCur(y);
w = word; // Carrys from previous row
diff = 0; // Carry from last column
car = *w; // Carry from last row
for (x=0;
x < width;
x++) {
// convert rgb to 256 grey scale
cur = (*r++ * 256) + diff + car;
new = cur / 256;
if (new > 255) {
*old++ = GreyMap[255];
diff = cur - (255 * 256);
}
else {
if (new < 0) {
*old++ = GreyMap[0];
diff = cur;
}
else {
*old++ = GreyMap[new];
diff = cur - (new * 256);
}
}
*w++ = (diff * 3)/8; // 3/8 to pixel below
car = *w; // carry to next pixel
*w = diff / 4; // 2/8 to pixel below right
diff = (diff * 3)/8; // 3/8 to pixel right;
}
}
}
else {
r = red;
g = green;
b = blue;
old = red;
AddMessageNo(MSG_INCOL);
if (Linear) {
AddMessageNo(MSG_LINEAR);
}
SetMax(height);
for (y=0;
y<height;
y++) {
SetCur(y);
w = word; // Carrys from previous row
diff = 0; // Carry from last column
car = *w; // Carry from last row
if (Linear) {
for (x=0;
x < width;
x++) {
// convert rgb to 256 grey scale
cur = (int)*r++ + (int)*g++ + (int)*b++ + diff + car;
new = cur / 3;
if (new > 255) {
*old++ = GreyMap[255];
diff = cur - (255 * 3);
}
else {
if (new < 0) {
*old++ = GreyMap[0];
diff = cur;
}
else {
*old++ = GreyMap[new];
diff = cur - (new * 3);
}
}
*w++ = (diff * 3)/8; // 3/8 to pixel below
car = *w; // carry to next pixel
*w = diff / 4; // 2/8 to pixel below right
diff = (diff * 3)/8; // 3/8 to pixel right;
}
}
else {
for (x=0;
x < width;
x++) {
// convert rgb to 256 grey scale
cur = (30 * (int)*r++) + (59 * (int)*g++) + (11 * (int)*b++) + diff + car;
new = cur / 100;
if (new > 255) {
*old++ = GreyMap[255];
diff = cur - (255 * 100);
}
else {
if (new < 0) {
*old++ = GreyMap[0];
diff = cur;
}
else {
*old++ = GreyMap[new];
diff = cur - (new * 100);
}
}
*w++ = (diff * 3)/8; // 3/8 to pixel below
car = *w; // carry to next pixel
*w = diff / 4; // 2/8 to pixel below right
diff = (diff * 3)/8; // 3/8 to pixel right;
}
}
}
}
c2p.bmap = (struct BitMap *)bitmap;
c2p.startX = 0;
c2p.startY = 0;
c2p.width = width;
c2p.height = height;
c2p.chunkybuffer = red;
ChunkyToPlanar(&c2p);
AddMessageNo(MSG_SILBM);
if (!NewBitMap) {
OkFlag = !mysaveilbm(&ilbm, (struct BitMap *)bitmap, GetMode(height,width,8,camg,0,FileName),
width, height, width, height,
palette, 256, 8, /* colortable */
mskNone, 0, /* masking, transparent */
NULL, NULL, /* chunklists */
(UBYTE *)FileName,8);
}
else {
OkFlag = TRUE;
}
// Close everything down cleanly
FreeIFF(ilbm.ParseInfo.iff);
}
else {
OkFlag = FALSE;
strcpy(ErrorMessage,GetMg(MSG_ERR_IFF));
}
if (!NewBitMap) {
MyFreeBitMap(bitmap,FileName);
}
}
else {
strcpy(ErrorMessage,GetMg(MSG_ERR_ALLOCBIT));
OkFlag = FALSE;
}
if (word) {
FreeVec(word);
}
return OkFlag;
}
/* save HAM6
* see SaveBW16()
*/
static BOOL
SaveHAM6(const UBYTE *FileName,USHORT width,USHORT height,
UBYTE *red, UBYTE *green, UBYTE *blue,UBYTE palette[][3], ULONG camg, struct BitMap *NewBitMap) {
UBYTE *r,*g,*b,*p;
UBYTE rr,gg,bb;
UBYTE *old;
UWORD x,y;
ULONG maxdiff;
ULONG diff;
LONG t;
UWORD k;
UWORD index=0;
BOOL OkFlag=FALSE;
UBYTE lr,lg,lb;
struct ILBMInfo ilbm = {0};
struct MyBitMap *bitmap;
struct c2pStruct c2p;
int *word = NULL,*wr,*wg,*wb;
int diffr,curr,newr,carr;
int diffg,curg,newg,carg;
int diffb,curb,newb,carb;
UBYTE *InvMap;
ULONG *Diffs = NULL;
int i,ir,ig,ib;
AddMessageNo(MSG_SHAM6);
bitmap = (struct MyBitMap *)NewBitMap;
if ((InvMap = AllocVec(4906,MEMF_ANY)) &&
(Diffs = AllocVec(4906*sizeof(ULONG),MEMF_ANY)) &&
(word = AllocVec((sizeof(int))*(width+1)*3,MEMF_CLEAR)) &&
((NewBitMap) || (bitmap = MyAllocBitMap(width,height,6,FileName)))) {
if (ilbm.ParseInfo.iff = AllocIFF()) {
AddMessageNo(MSG_BM);
// Compute inverse color map
for (i = 0; i < 4096; ++i) {
ir = RED6(i);
ig = GREEN6(i);
ib = BLUE6(i);
// Find closest color
maxdiff = 0x7FFFFFFF;
p = &(palette[0][0]);
for (k = 0;
(k < 16) && maxdiff;
++k) {
t = ir - (int)*p++;
diff = t*t * 2;
if (diff < maxdiff) {
t = ig - (int)*p++;
diff += t*t * 4;
if (diff < maxdiff) {
t = ib - (int)*p++;
diff += t*t;
if (diff < maxdiff) {
maxdiff = diff;
index = k;
}
}
else {
++p;
}
}
else {
++p;
++p;
}
}
InvMap[i] = index;
Diffs[i] = maxdiff;
}
r = red;
g = green;
b = blue;
old = red;
AddMessageNo(MSG_REMAP);
SetMax(height);
for (y=0;
y<height;
y++) {
SetCur(y);
lr = palette[0][0];
lg = palette[0][1];
lb = palette[0][2];
wr = word; // Carrys from previous row
diffr = 0; // Carry from last column
carr = *wr; // Carry from last row
wg = word+(width+1);
diffg = 0;
carg = *wg;
wb = word+(2*(width+1));
diffb = 0;
carb = *wb;
for (x=0;
x < width;
x++) {
curr = ((int)*r * 256) + diffr + carr;
newr = curr / 256;
if (newr > 255) {
rr = 255;
}
else {
if (newr < 0) {
rr = 0;
}
else {
rr = newr;
}
}
curg = ((int)*g * 256) + diffg + carg;
newg = curg / 256;
if (newg > 255) {
gg = 255;
}
else {
if (newg < 0) {
gg = 0;
}
else {
gg = newg;
}
}
curb = ((int)*b * 256) + diffb + carb;
newb = curb / 256;
if (newb > 255) {
bb = 255;
}
else {
if (newb < 0) {
bb = 0;
}
else {
bb = newb;
}
}
// colour if we use HAM to change R or G or B
palette[16][0] = rr;
palette[16][1] = lg;
palette[16][2] = lb;
palette[17][0] = lr;
palette[17][1] = gg;
palette[17][2] = lb;
palette[18][0] = lr;
palette[18][1] = lg;
palette[18][2] = bb;
// Find closest color
index = InvMap[RGB6(rr,gg,bb)];
maxdiff = Diffs[RGB6(rr,gg,bb)];
p = &(palette[18][2]);
for (k = 0;
(k < 3) && maxdiff;
++k) {
t = (int)bb - (int)*p--;
diff = t*t;
if (diff < maxdiff) {
t = (int)gg - (int)*p--;
diff += t*t * 4;
if (diff < maxdiff) {
t = (int)rr - (int)*p--;
diff += t*t * 2;
if (diff < maxdiff) {
maxdiff = diff;
index = 18 - k;
}
}
else {
--p;
}
}
else {
--p;
--p;
}
}
lr = palette[index][0];
lg = palette[index][1];
lb = palette[index][2];
// FS dither
diffr = curr - (lr * 256);
*wr++ = (diffr * 3)/8; // 3/8 to pixel below
carr = *wr; // carry to next pixel
*wr = diffr / 4; // 2/8 to pixel below right
diffr = (diffr * 3)/8; // 3/8 to pixel right;
diffg = curg - (lg * 256);
*wg++ = (diffg * 3)/8;
carg = *wg;
*wg = diffg / 4;
diffg = (diffg * 3)/8;
diffb = curb - (lb * 256);
*wb++ = (diffb * 3)/8;
carb = *wb;
*wb = diffb / 4;
diffb = (diffb * 3)/8;
// Set HAM bits if required
if (index == 16) {
*old++ = (rr>>4) | 0x20;
}
else {
if (index == 17) {
*old++ = (gg>>4) | 0x30;
}
else {
if (index == 18) {
*old++ = (bb>>4) | 0x10;
}
else {
*old++ = index;
}
}
}
r++;
g++;
b++;
}
}
c2p.bmap = (struct BitMap *)bitmap;
c2p.startX = 0;
c2p.startY = 0;
c2p.width = width;
c2p.height = height;
c2p.chunkybuffer = red;
ChunkyToPlanar(&c2p);
AddMessageNo(MSG_SILBM);
if (!NewBitMap) {
OkFlag = !mysaveilbm(&ilbm, (struct BitMap *)bitmap, GetMode(height,width,6,camg,DIPF_IS_HAM,FileName),
width, height, width, height,
palette, 16, 8, /* colortable */
mskNone, 0, /* masking, transparent */
NULL, NULL, /* chunklists */
(UBYTE *)FileName,6);
}
else {
OkFlag = TRUE;
}
// Close everything down cleanly
FreeIFF(ilbm.ParseInfo.iff);
}
else {
strcpy(ErrorMessage,GetMg(MSG_ERR_IFF));
OkFlag = FALSE;
}
if (!NewBitMap) {
MyFreeBitMap(bitmap,FileName);
}
}
else {
strcpy(ErrorMessage,GetMg(MSG_ERR_ALLOCBIT));
OkFlag = FALSE;
}
if (word) {
FreeVec(word);
}
if (InvMap) {
FreeVec(InvMap);
}
if (Diffs) {
FreeVec(Diffs);
}
return OkFlag;
}
/* save HAM8
* see SaveHAM6()
*/
static BOOL
SaveHAM8(const UBYTE *FileName,USHORT width,USHORT height,
UBYTE *red, UBYTE *green, UBYTE *blue, UBYTE palette[][3], ULONG camg, struct BitMap *NewBitMap) {
UBYTE *r,*g,*b,*p;
UBYTE rr,gg,bb;
UBYTE *old;
UWORD x,y;
ULONG maxdiff;
ULONG diff;
LONG t;
UWORD k;
UWORD index=0;
BOOL OkFlag=FALSE;
UBYTE lr,lg,lb;
struct ILBMInfo ilbm = {0};
struct MyBitMap *bitmap;
struct c2pStruct c2p;
int *word,*wr,*wg,*wb;
int diffr,curr,newr,carr;
int diffg,curg,newg,carg;
int diffb,curb,newb,carb;
AddMessageNo(MSG_SHAM8);
bitmap = (struct MyBitMap *)NewBitMap;
if ((word = AllocVec((sizeof(int))*(width+1)*3,MEMF_CLEAR)) &&
((NewBitMap) || (bitmap = MyAllocBitMap(width,height,8,FileName)))) {
if (ilbm.ParseInfo.iff = AllocIFF()) {
r = red;
g = green;
b = blue;
old = red;
AddMessageNo(MSG_REMAP);
SetMax(height);
for (y=0;
y<height;
y++) {
SetCur(y);
lr = palette[0][0];
lg = palette[0][1];
lb = palette[0][2];
wr = word; // Carrys from previous row
diffr = 0; // Carry from last column
carr = *wr; // Carry from last row
wg = word+(width+1);
diffg = 0;
carg = *wg;
wb = word+(2*(width+1));
diffb = 0;
carb = *wb;
for (x=0;
x < width;
x++) {
curr = ((int)*r * 256) + diffr + carr;
newr = curr / 256;
if (newr > 255) {
rr = 255;
}
else {
if (newr < 0) {
rr = 0;
}
else {
rr = newr;
}
}
curg = ((int)*g * 256) + diffg + carg;
newg = curg / 256;
if (newg > 255) {
gg = 255;
}
else {
if (newg < 0) {
gg = 0;
}
else {
gg = newg;
}
}
curb = ((int)*b * 256) + diffb + carb;
newb = curb / 256;
if (newb > 255) {
bb = 255;
}
else {
if (newb < 0) {
bb = 0;
}
else {
bb = newb;
}
}
palette[64][0] = rr;
palette[64][1] = lg;
palette[64][2] = lb;
palette[65][0] = lr;
palette[65][1] = gg;
palette[65][2] = lb;
palette[66][0] = lr;
palette[66][1] = lg;
palette[66][2] = bb;
// Find closest color
maxdiff = 0x7FFFFFFF;
p = &(palette[66][2]);
for (k = 0;
(k < 67) && maxdiff;
++k) {
t = (int)bb - (int)*p--;
diff = t*t;
if (diff < maxdiff) {
t = (int)gg - (int)*p--;
diff += t*t * 4;
if (diff < maxdiff) {
t = (int)rr - (int)*p--;
diff += t*t * 2;
if (diff < maxdiff) {
maxdiff = diff;
index = 66 - k;
}
}
else {
--p;
}
}
else {
--p;
--p;
}
}
lr = palette[index][0];
lg = palette[index][1];
lb = palette[index][2];
// FS dither
diffr = curr - (lr * 256);
*wr++ = (diffr * 3)/8; // 3/8 to pixel below
carr = *wr; // carry to next pixel
*wr = diffr / 4; // 2/8 to pixel below right
diffr = (diffr * 3)/8; // 3/8 to pixel right;
diffg = curg - (lg * 256);
*wg++ = (diffg * 3)/8;
carg = *wg;
*wg = diffg / 4;
diffg = (diffg * 3)/8;
diffb = curb - (lb * 256);
*wb++ = (diffb * 3)/8;
carb = *wb;
*wb = diffb / 4;
diffb = (diffb * 3)/8;
if (index == 64) {
*old++ = (rr>>2) | 0x80;
}
else {
if (index == 65) {
*old++ = (gg>>2) | 0xc0;
}
else {
if (index == 66) {
*old++ = (bb>>2) | 0x40;
}
else {
*old++ = index;
}
}
}
r++;
g++;
b++;
}
}
c2p.bmap = (struct BitMap *)bitmap;
c2p.startX = 0;
c2p.startY = 0;
c2p.width = width;
c2p.height = height;
c2p.chunkybuffer = red;
ChunkyToPlanar(&c2p);
AddMessageNo(MSG_SILBM);
if (!NewBitMap) {
OkFlag = !mysaveilbm(&ilbm, (struct BitMap *)bitmap, GetMode(height,width,8,camg,DIPF_IS_HAM,FileName),
width, height, width, height,
palette, 64, 8, /* colortable */
mskNone, 0, /* masking, transparent */
NULL, NULL, /* chunklists */
(UBYTE *)FileName,8);
}
else {
OkFlag = TRUE;
}
// Close everything down cleanly
FreeIFF(ilbm.ParseInfo.iff);
}
else {
strcpy(ErrorMessage,GetMg(MSG_ERR_IFF));
OkFlag = FALSE;
}
if (!NewBitMap) {
MyFreeBitMap(bitmap,FileName);
}
}
else {
strcpy(ErrorMessage,GetMg(MSG_ERR_ALLOCBIT));
OkFlag = FALSE;
}
if (word) {
FreeVec(word);
}
return OkFlag;
}
/* save 24
* see Save24()
*/
static BOOL
Save24(const UBYTE *FileName,USHORT width,USHORT height,
UBYTE *red, UBYTE *green, UBYTE *blue, ULONG camg) {
struct ILBMInfo ilbm = {0}; // IFF stuff to save
BOOL OkFlag;
UBYTE *Planes[24]={0};
struct MyBitMap *bitmap;
int i;
struct c2pStruct c2p;
AddMessageNo(MSG_S24);
// Set up BitMap
if (bitmap = MyAllocBitMap(width,height,24,FileName)) {
for (i=0; i<24; i++) {
Planes[i] = bitmap->BitMap.Planes[i];
}
if (ilbm.ParseInfo.iff = AllocIFF()) {
// i.e. 24 bit ILBM?
// so convert chunky to planar
bitmap->BitMap.Depth = 8;
c2p.bmap = &(bitmap->BitMap);
c2p.startX = 0;
c2p.startY = 0;
c2p.width = width;
c2p.height = height;
c2p.chunkybuffer = red;
ChunkyToPlanar(&c2p);
bitmap->BitMap.Planes[0] = Planes[8];
bitmap->BitMap.Planes[1] = Planes[9];
bitmap->BitMap.Planes[2] = Planes[10];
bitmap->BitMap.Planes[3] = Planes[11];
bitmap->BitMap.Planes[4] = Planes[12];
bitmap->BitMap.Planes[5] = Planes[13];
bitmap->BitMap.Planes[6] = Planes[14];
bitmap->BitMap.Planes[7] = Planes[15];
c2p.chunkybuffer = green;
ChunkyToPlanar(&c2p);
bitmap->BitMap.Planes[0] = Planes[16];
bitmap->BitMap.Planes[1] = Planes[17];
bitmap->BitMap.Planes[2] = Planes[18];
bitmap->BitMap.Planes[3] = Planes[19];
bitmap->BitMap.Planes[4] = Planes[20];
bitmap->BitMap.Planes[5] = Planes[21];
bitmap->BitMap.Planes[6] = Planes[22];
bitmap->BitMap.Planes[7] = Planes[23];
c2p.chunkybuffer = blue;
ChunkyToPlanar(&c2p);
InitBitMap((struct BitMap *)bitmap,24,width,height);
for (i=0; i<24; i++) {
bitmap->BitMap.Planes[i] = Planes[i];
}
AddMessageNo(MSG_SILBM);
OkFlag = !mysaveilbm(&ilbm, (struct BitMap *)bitmap, GetMode(height,width,24,camg,0,FileName),
width, height, width, height,
NULL, 0, 0, /* colortable */
mskNone, 0, /* masking, transparent */
NULL, NULL, /* chunklists */
(UBYTE *)FileName,24);
// Close everything down cleanly
FreeIFF(ilbm.ParseInfo.iff);
}
else {
strcpy(ErrorMessage,GetMg(MSG_ERR_IFF));
OkFlag = FALSE;
}
MyFreeBitMap(bitmap,FileName);
}
else {
strcpy(ErrorMessage,GetMg(MSG_ERR_ALLOCBIT));
OkFlag = FALSE;
}
return OkFlag;
}
static BOOL
SavePPM(const UBYTE *FileName,USHORT width,USHORT height,
UBYTE *red, UBYTE *green, UBYTE *blue, UWORD jpeg) {
int x,y;
int i,j;
UBYTE *arrayr,*arrayg,*arrayb;
BPTR fh; // File handle for PPM
BOOL OkFlag = TRUE;
UBYTE buffer[32];
char jpegbuf[120];
char jpegpip[32];
char jpegcom[256];
char *jfilename;
if (!jpeg) {
AddMessageNo(MSG_SPPM);
jfilename = FileName;
}
else {
if (jpeg == 1) {
AddMessageNo(MSG_SJPEG);
}
else {
AddMessageNo(MSG_SPNG);
}
if (((jpeg == 1) && (GetVar("mpimage/cjpeg",jpegbuf,119,0) > 0)) ||
((jpeg == 2) && (GetVar("mpimage/pnmtopng",jpegbuf,119,0) > 0))) {
if (fh = Open(FileName,MODE_NEWFILE)) {
Close(fh);
}
else {
strcpy(ErrorMessage,GetMg(MSG_ERR_OPENOUT));
return FALSE;
}
sprintf(jpegpip,"%s%ld","PIPE:",red);
AddMessage(jpegpip);
sprintf(jpegcom,jpegbuf,jpegpip,FileName);
SystemTags(jpegcom,
SYS_Input, 0,
SYS_Output, 0,
SYS_Asynch, TRUE,
NP_StackSize, 16000,
NP_Name, (jpeg == 1) ? "MPImage CJPEG task" : "MPImage PNMTOPNG task",
TAG_END);
jfilename = jpegpip;
j = 0;
for (i = 0;
(i < 20) && (!j);
++i) {
BYTE pri;
// Try to write to file - if this works then wait again
pri = SetTaskPri(FindTask(0),21);
if (fh = Open(FileName,MODE_NEWFILE)) {
Close(fh);
if (jpeg == 1) {
AddMessageNo(MSG_WCJPEG);
}
else {
AddMessageNo(MSG_WPNMTOPNG);
}
Delay(50*1);
}
else {
j = 1;
}
SetTaskPri(FindTask(0),pri);
}
if (!j) {
if (jpeg == 1) {
strcpy(ErrorMessage,GetMg(MSG_ERR_CJPEG));
}
else {
strcpy(ErrorMessage,GetMg(MSG_ERR_PNMTOPNG));
}
return FALSE;
}
}
else {
if (jpeg == 1) {
strcpy(ErrorMessage,GetMg(MSG_ERR_GCJPEG));
}
else {
strcpy(ErrorMessage,GetMg(MSG_ERR_GPNMTOPNG));
}
return FALSE;
}
}
if (fh = Open((UBYTE *)jfilename,MODE_NEWFILE)) {
if ((red == green) && (red == blue)) { // grey scale input
AddMessageNo(MSG_SP5);
sprintf(buffer,"P5\n%ld %ld\n255\n",width,height);
FPuts(fh,buffer);
if (FWrite(fh,red,width,height) != height) {
OkFlag = FALSE;
strcpy(ErrorMessage,GetMg(MSG_ERR_WRITE));
}
}
else {
AddMessageNo(MSG_SP6);
sprintf(buffer,"P6\n%ld %ld\n255\n",width,height);
FPuts(fh,buffer);
arrayr=red;
arrayg=green;
arrayb=blue;
SetMax(height);
// loop thru lines
for (y=0;
(y<height) && OkFlag;
y++) {
SetCur(y);
// Loop thru columns
for (x=0;
(x < width) && OkFlag;
x++) {
if (FPutC(fh,*arrayr++) == EOF) {
OkFlag = FALSE;
}
else {
if (FPutC(fh,*arrayg++) == EOF) {
OkFlag = FALSE;
}
else {
if (FPutC(fh,*arrayb++) == EOF) {
OkFlag = FALSE;
}
}
}
if (!OkFlag) {
strcpy(ErrorMessage,GetMg(MSG_ERR_WRITE));
}
}
}
}
if (!Close(fh)) {
strcpy(ErrorMessage,GetMg(MSG_ERR_CLOSE));
OkFlag = FALSE;
}
}
else {
strcpy(ErrorMessage,GetMg(MSG_ERR_OPENOUT));
OkFlag = FALSE;
}
return OkFlag;
}
static BOOL
SaveColour(const UBYTE *FileName,USHORT width,USHORT height,
UBYTE *red, UBYTE *green, UBYTE *blue, ULONG camg, ULONG numcols, struct BitMap *NewBitMap) {
UBYTE *r,*g,*b,*p;
UBYTE rr,gg,bb;
UBYTE *old;
UWORD x,y;
ULONG maxdiff;
ULONG diff;
LONG t;
UWORD k;
UWORD index=0;
BOOL OkFlag=FALSE;
struct ILBMInfo ilbm = {0};
struct MyBitMap *bitmap;
struct c2pStruct c2p;
int *word,*wr,*wg,*wb;
int diffr,curr,newr,carr;
int diffg,curg,newg,carg;
int diffb,curb,newb,carb;
int Depth;
AddMessageNo(MSG_SCOL);
bitmap = (struct MyBitMap *)NewBitMap;
if (numcols > 128) {
Depth = 8;
}
else {
if (numcols > 64) {
Depth = 7;
}
else {
if (numcols > 32) {
Depth = 6;
}
else {
if (numcols > 16) {
Depth = 5;
}
else {
if (numcols > 8) {
Depth = 4;
}
else {
if (numcols > 4) {
Depth = 3;
}
else {
if (numcols > 2) {
Depth = 2;
}
else {
Depth = 1;
}
}
}
}
}
}
}
if ((word = AllocVec((sizeof(int))*(width+1)*3,MEMF_CLEAR)) &&
((NewBitMap) || (bitmap = MyAllocBitMap(width,height,Depth,FileName)))) {
if (ilbm.ParseInfo.iff = AllocIFF()) {
r = red;
g = green;
b = blue;
old = red;
AddMessageNo(MSG_REMAP);
SetMax(height);
for (y=0;
y<height;
y++) {
SetCur(y);
wr = word; // Carrys from previous row
diffr = 0; // Carry from last column
carr = *wr; // Carry from last row
wg = word+(width+1);
diffg = 0;
carg = *wg;
wb = word+(2*(width+1));
diffb = 0;
carb = *wb;
for (x=0;
x < width;
x++) {
curr = ((int)*r * 256) + diffr + carr;
newr = curr / 256;
if (newr > 255) {
rr = 255;
}
else {
if (newr < 0) {
rr = 0;
}
else {
rr = newr;
}
}
curg = ((int)*g * 256) + diffg + carg;
newg = curg / 256;
if (newg > 255) {
gg = 255;
}
else {
if (newg < 0) {
gg = 0;
}
else {
gg = newg;
}
}
curb = ((int)*b * 256) + diffb + carb;
newb = curb / 256;
if (newb > 255) {
bb = 255;
}
else {
if (newb < 0) {
bb = 0;
}
else {
bb = newb;
}
}
// Find closest color
maxdiff = 0x7FFFFFFF;
p = &(MyPalette[0][0]);
for (k = 0;
(k < numcols) && maxdiff;
++k) {
t = (int)rr - (int)*p++;
diff = t*t * 2;
if (diff < maxdiff) {
t = (int)gg - (int)*p++;
diff += t*t * 4;
if (diff < maxdiff) {
t = (int)bb - (int)*p++;
diff += t*t;
if (diff < maxdiff) {
maxdiff = diff;
index = k;
}
}
else {
++p;
}
}
else {
++p;
++p;
}
}
// FS dither
diffr = curr - (MyPalette[index][0] * 256);
*wr++ = (diffr * 3)/8; // 3/8 to pixel below
carr = *wr; // carry to next pixel
*wr = diffr / 4; // 2/8 to pixel below right
diffr = (diffr * 3)/8; // 3/8 to pixel right;
diffg = curg - (MyPalette[index][1] * 256);
*wg++ = (diffg * 3)/8;
carg = *wg;
*wg = diffg / 4;
diffg = (diffg * 3)/8;
diffb = curb - (MyPalette[index][2] * 256);
*wb++ = (diffb * 3)/8;
carb = *wb;
*wb = diffb / 4;
diffb = (diffb * 3)/8;
*old++ = index;
r++;
g++;
b++;
}
}
c2p.bmap = (struct BitMap *)bitmap;
c2p.startX = 0;
c2p.startY = 0;
c2p.width = width;
c2p.height = height;
c2p.chunkybuffer = red;
ChunkyToPlanar(&c2p);
AddMessageNo(MSG_SILBM);
if (!NewBitMap) {
OkFlag = !mysaveilbm(&ilbm, (struct BitMap *)bitmap,GetMode(height,width,Depth,camg,0,FileName),
width, height, width, height,
MyPalette, numcols, 8, /* colortable */
mskNone, 0, /* masking, transparent */
NULL, NULL, /* chunklists */
(UBYTE *)FileName,Depth);
}
else {
OkFlag = TRUE;
}
// Close everything down cleanly
FreeIFF(ilbm.ParseInfo.iff);
}
else {
strcpy(ErrorMessage,GetMg(MSG_ERR_IFF));
OkFlag = FALSE;
}
if (!NewBitMap) {
MyFreeBitMap(bitmap,FileName);
}
}
else {
strcpy(ErrorMessage,GetMg(MSG_ERR_ALLOCBIT));
OkFlag = FALSE;
}
if (word) {
FreeVec(word);
}
return OkFlag;
}
static BOOL
SaveColour12(const UBYTE *FileName,USHORT width,USHORT height,
UBYTE *red, UBYTE *green, UBYTE *blue, ULONG camg, ULONG numcols, struct BitMap *NewBitMap) {
UBYTE *r,*g,*b,*p;
UBYTE rr,gg,bb;
UBYTE *old;
UWORD x,y;
ULONG maxdiff;
ULONG diff;
LONG t;
UWORD k;
UWORD index=0;
BOOL OkFlag=FALSE;
struct ILBMInfo ilbm = {0};
struct MyBitMap *bitmap;
struct c2pStruct c2p;
int *word = NULL,*wr,*wg,*wb;
int diffr,curr,newr,carr;
int diffg,curg,newg,carg;
int diffb,curb,newb,carb;
UBYTE *InvMap;
int i,ir,ig,ib;
int Depth;
AddMessageNo(MSG_S12);
bitmap = (struct MyBitMap *)NewBitMap;
if (numcols > 128) {
Depth = 8;
}
else {
if (numcols > 64) {
Depth = 7;
}
else {
if (numcols > 32) {
Depth = 6;
}
else {
if (numcols > 16) {
Depth = 5;
}
else {
if (numcols > 8) {
Depth = 4;
}
else {
if (numcols > 4) {
Depth = 3;
}
else {
if (numcols > 2) {
Depth = 2;
}
else {
Depth = 1;
}
}
}
}
}
}
}
if ((InvMap = AllocVec(4906,MEMF_ANY)) &&
(word = AllocVec((sizeof(int))*(width+1)*3,MEMF_CLEAR)) &&
((NewBitMap) || (bitmap = MyAllocBitMap(width,height,Depth,FileName)))) {
if (ilbm.ParseInfo.iff = AllocIFF()) {
AddMessageNo(MSG_BM);
// Compute inverse color map
for (i = 0; i < 4096; ++i) {
ir = RED6(i);
ig = GREEN6(i);
ib = BLUE6(i);
// Find closest color
maxdiff = 0x7FFFFFFF;
p = &(MyPalette[0][0]);
for (k = 0;
(k < numcols) && maxdiff;
++k) {
t = ir - (int)*p++;
diff = t*t * 2;
if (diff < maxdiff) {
t = ig - (int)*p++;
diff += t*t * 4;
if (diff < maxdiff) {
t = ib - (int)*p++;
diff += t*t;
if (diff < maxdiff) {
maxdiff = diff;
index = k;
}
}
else {
++p;
}
}
else {
++p;
++p;
}
}
InvMap[i] = index;
}
r = red;
g = green;
b = blue;
old = red;
AddMessageNo(MSG_REMAP);
SetMax(height);
for (y=0;
y<height;
y++) {
SetCur(y);
wr = word; // Carrys from previous row
diffr = 0; // Carry from last column
carr = *wr; // Carry from last row
wg = word+(width+1);
diffg = 0;
carg = *wg;
wb = word+(2*(width+1));
diffb = 0;
carb = *wb;
for (x=0;
x < width;
x++) {
curr = ((int)*r * 256) + diffr + carr;
newr = curr / 256;
if (newr > 255) {
rr = 255;
}
else {
if (newr < 0) {
rr = 0;
}
else {
rr = newr;
}
}
curg = ((int)*g * 256) + diffg + carg;
newg = curg / 256;
if (newg > 255) {
gg = 255;
}
else {
if (newg < 0) {
gg = 0;
}
else {
gg = newg;
}
}
curb = ((int)*b * 256) + diffb + carb;
newb = curb / 256;
if (newb > 255) {
bb = 255;
}
else {
if (newb < 0) {
bb = 0;
}
else {
bb = newb;
}
}
// Find closest color
index = InvMap[RGB6(rr,gg,bb)];
// FS dither
diffr = curr - (MyPalette[index][0] * 256);
*wr++ = (diffr * 3)/8; // 3/8 to pixel below
carr = *wr; // carry to next pixel
*wr = diffr / 4; // 2/8 to pixel below right
diffr = (diffr * 3)/8; // 3/8 to pixel right;
diffg = curg - (MyPalette[index][1] * 256);
*wg++ = (diffg * 3)/8;
carg = *wg;
*wg = diffg / 4;
diffg = (diffg * 3)/8;
diffb = curb - (MyPalette[index][2] * 256);
*wb++ = (diffb * 3)/8;
carb = *wb;
*wb = diffb / 4;
diffb = (diffb * 3)/8;
*old++ = index;
r++;
g++;
b++;
}
}
c2p.bmap = (struct BitMap *)bitmap;
c2p.startX = 0;
c2p.startY = 0;
c2p.width = width;
c2p.height = height;
c2p.chunkybuffer = red;
ChunkyToPlanar(&c2p);
AddMessageNo(MSG_SILBM);
if (!NewBitMap) {
OkFlag = !mysaveilbm(&ilbm, (struct BitMap *)bitmap, GetMode(height,width,Depth,camg,0,FileName),
width, height, width, height,
MyPalette, numcols, 8, /* colortable */
mskNone, 0, /* masking, transparent */
NULL, NULL, /* chunklists */
(UBYTE *)FileName,Depth);
}
else {
OkFlag = TRUE;
}
// Close everything down cleanly
FreeIFF(ilbm.ParseInfo.iff);
}
else {
strcpy(ErrorMessage,GetMg(MSG_ERR_IFF));
OkFlag = FALSE;
}
if (!NewBitMap) {
MyFreeBitMap(bitmap,FileName);
}
}
else {
strcpy(ErrorMessage,GetMg(MSG_ERR_ALLOCBIT));
OkFlag = FALSE;
}
if (word) {
FreeVec(word);
}
if (InvMap) {
FreeVec(InvMap);
}
return OkFlag;
}
static BOOL
SaveEHB(const UBYTE *FileName,USHORT width,USHORT height,
UBYTE *red, UBYTE *green, UBYTE *blue, ULONG camg, struct BitMap *NewBitMap) {
UBYTE *r,*g,*b,*p;
UBYTE rr,gg,bb;
UBYTE *old;
UWORD x,y;
ULONG maxdiff;
ULONG diff;
LONG t;
UWORD k;
UWORD index=0;
BOOL OkFlag=FALSE;
struct ILBMInfo ilbm = {0};
struct MyBitMap *bitmap;
struct c2pStruct c2p;
int *word = NULL,*wr,*wg,*wb;
int diffr,curr,newr,carr;
int diffg,curg,newg,carg;
int diffb,curb,newb,carb;
UBYTE *InvMap;
int i,ir,ig,ib,j;
AddMessageNo(MSG_SEHB);
bitmap = (struct MyBitMap *)NewBitMap;
for (i = 0; i < 32; ++i) {
for (j = 0; j < 3; ++j) {
MyPalette[i+32][j] = (MyPalette[i][j])>>1;
}
}
if ((InvMap = AllocVec(4906,MEMF_ANY)) &&
(word = AllocVec((sizeof(int))*(width+1)*3,MEMF_CLEAR)) &&
((NewBitMap) || (bitmap = MyAllocBitMap(width,height,6,FileName)))) {
if (ilbm.ParseInfo.iff = AllocIFF()) {
AddMessageNo(MSG_BM);
// Compute inverse color map
for (i = 0; i < 4096; ++i) {
ir = RED6(i);
ig = GREEN6(i);
ib = BLUE6(i);
// Find closest color
maxdiff = 0x7FFFFFFF;
p = &(MyPalette[0][0]);
for (k = 0;
(k < 64) && maxdiff;
++k) {
t = ir - (int)*p++;
diff = t*t * 2;
if (diff < maxdiff) {
t = ig - (int)*p++;
diff += t*t * 4;
if (diff < maxdiff) {
t = ib - (int)*p++;
diff += t*t;
if (diff < maxdiff) {
maxdiff = diff;
index = k;
}
}
else {
++p;
}
}
else {
++p;
++p;
}
}
InvMap[i] = index;
}
r = red;
g = green;
b = blue;
old = red;
AddMessageNo(MSG_REMAP);
SetMax(height);
for (y=0;
y<height;
y++) {
SetCur(y);
wr = word; // Carrys from previous row
diffr = 0; // Carry from last column
carr = *wr; // Carry from last row
wg = word+(width+1);
diffg = 0;
carg = *wg;
wb = word+(2*(width+1));
diffb = 0;
carb = *wb;
for (x=0;
x < width;
x++) {
curr = ((int)*r * 256) + diffr + carr;
newr = curr / 256;
if (newr > 255) {
rr = 255;
}
else {
if (newr < 0) {
rr = 0;
}
else {
rr = newr;
}
}
curg = ((int)*g * 256) + diffg + carg;
newg = curg / 256;
if (newg > 255) {
gg = 255;
}
else {
if (newg < 0) {
gg = 0;
}
else {
gg = newg;
}
}
curb = ((int)*b * 256) + diffb + carb;
newb = curb / 256;
if (newb > 255) {
bb = 255;
}
else {
if (newb < 0) {
bb = 0;
}
else {
bb = newb;
}
}
// Find closest color
index = InvMap[RGB6(rr,gg,bb)];
// FS dither
diffr = curr - (MyPalette[index][0] * 256);
*wr++ = (diffr * 3)/8; // 3/8 to pixel below
carr = *wr; // carry to next pixel
*wr = diffr / 4; // 2/8 to pixel below right
diffr = (diffr * 3)/8; // 3/8 to pixel right;
diffg = curg - (MyPalette[index][1] * 256);
*wg++ = (diffg * 3)/8;
carg = *wg;
*wg = diffg / 4;
diffg = (diffg * 3)/8;
diffb = curb - (MyPalette[index][2] * 256);
*wb++ = (diffb * 3)/8;
carb = *wb;
*wb = diffb / 4;
diffb = (diffb * 3)/8;
*old++ = index;
r++;
g++;
b++;
}
}
c2p.bmap = (struct BitMap *)bitmap;
c2p.startX = 0;
c2p.startY = 0;
c2p.width = width;
c2p.height = height;
c2p.chunkybuffer = red;
ChunkyToPlanar(&c2p);
AddMessageNo(MSG_SILBM);
if (!NewBitMap) {
OkFlag = !mysaveilbm(&ilbm, (struct BitMap *)bitmap, GetMode(height,width,6,camg,DIPF_IS_EXTRAHALFBRITE,FileName),
width, height, width, height,
MyPalette, 32, 8, /* colortable */
mskNone, 0, /* masking, transparent */
NULL, NULL, /* chunklists */
(UBYTE *)FileName,6);
}
else {
OkFlag = TRUE;
}
// Close everything down cleanly
FreeIFF(ilbm.ParseInfo.iff);
}
else {
strcpy(ErrorMessage,GetMg(MSG_ERR_IFF));
OkFlag = FALSE;
}
if (!NewBitMap) {
MyFreeBitMap(bitmap,FileName);
}
}
else {
strcpy(ErrorMessage,GetMg(MSG_ERR_ALLOCBIT));
OkFlag = FALSE;
}
if (word) {
FreeVec(word);
}
if (InvMap) {
FreeVec(InvMap);
}
return OkFlag;
}
// Note returns 0 for success!
static LONG
mysaveilbm(struct ILBMInfo *ilbm,
struct BitMap *bitmap, ULONG modeid,
WORD width, WORD height, WORD pagewidth, WORD pageheight,
UBYTE col[][3], UWORD count, UWORD bitspergun,
WORD masking, WORD transparentColor,
struct Chunk *chunklist1, struct Chunk *chunklist2,
UBYTE *filename, int Depth) {
if (filename && *filename) {
return saveilbm(ilbm,bitmap,modeid,width,height,pagewidth,pageheight,col,count,bitspergun,
masking,transparentColor,chunklist1,chunklist2,filename);
}
else {
struct Screen* Screen;
struct Rectangle Rectangle;
struct Window *Window;
int l,temp;
int i;
struct Message *msg;
ULONG error;
LONG okflag=1;
AddMessageNo(MSG_DISPLAY);
if (QueryOverscan(modeid, &Rectangle, OSCAN_MAX)) {
if ((temp = (Rectangle.MaxX - Rectangle.MinX + 1)) > width) {
l = (temp-width)/2 + Rectangle.MinX;
Rectangle.MinX = l;
Rectangle.MaxX = l + width - 1;
}
else {
l = Rectangle.MinX;
}
if (Screen = OpenScreenTags(NULL,
SA_Left, l,
SA_Top, Rectangle.MinY,
SA_Width, width,
SA_Height, height,
SA_Depth, Depth,
SA_ShowTitle, FALSE,
SA_Quiet, TRUE,
SA_Type, CUSTOMSCREEN,
SA_DisplayID, modeid,
SA_DClip, &Rectangle,
SA_AutoScroll, TRUE,
SA_ErrorCode, &error,
SA_BitMap, bitmap,
// SA_BackFill, LAYERS_NOBACKFILL,
TAG_END)) {
if (8 == bitspergun) {
for (i = 0; i < count; ++i) {
SetRGB32(&(Screen->ViewPort),i,(col[i][0])<<24,(col[i][1])<<24,(col[i][2])<<24);
}
}
else {
LoadRGB4(&(Screen->ViewPort),(UWORD *)col,count);
}
if (Window = OpenWindowTags(NULL,
WA_Left, 0,
WA_Top, Screen->BarHeight+1,
WA_Width, width,
WA_Height, height - Screen->BarHeight - 1,
WA_IDCMP, IDCMP_VANILLAKEY,
WA_CustomScreen, Screen,
WA_Backdrop, TRUE,
WA_Borderless, TRUE,
WA_NoCareRefresh, TRUE,
WA_Activate, TRUE,
WA_RMBTrap, TRUE,
WA_BackFill, LAYERS_NOBACKFILL,
TAG_END)) {
AddMessageNo(MSG_WAITKEY);
WaitPort(Window->UserPort);
while (msg = GetMsg(Window->UserPort)) {
ReplyMsg(msg);
}
okflag = 0;
CloseWindow(Window);
}
else {
strcpy(ErrorMessage,GetMg(MSG_ERR_WINDOW));
}
CloseScreen(Screen);
}
else {
strcpy(ErrorMessage,GetMg(MSG_ERR_SCREEN));
switch(error) {
case OSERR_NOMONITOR:
strcat(ErrorMessage,GetMg(MSG_ERR_NOMON));
break;
case OSERR_NOCHIPS:
strcat(ErrorMessage,GetMg(MSG_ERR_OLDCHIP));
break;
case OSERR_NOMEM:
strcat(ErrorMessage,GetMg(MSG_ERR_NOMEM));
break;
case OSERR_NOCHIPMEM:
strcat(ErrorMessage,GetMg(MSG_ERR_NOCHIP));
break;
case OSERR_UNKNOWNMODE:
strcat(ErrorMessage,GetMg(MSG_ERR_NOMODE));
break;
case OSERR_TOODEEP:
strcat(ErrorMessage,GetMg(MSG_ERR_DEEP));
break;
default:
strcat(ErrorMessage,GetMg(MSG_ERR_UNK));
break;
}
}
}
else {
strcpy(ErrorMessage,GetMg(MSG_ERR_QOS));
}
return okflag;
}
}
static BOOL SaveDCTV(const UBYTE *FileName,USHORT width,USHORT height,
UBYTE *red, UBYTE *green, UBYTE *blue, ULONG camg,BOOL dctv4, struct BitMap *NewBitMap) {
int i;
BOOL OkFlag=FALSE;
struct ILBMInfo ilbm = {0};
struct MyBitMap *bitmap;
int Depth;
struct DCTVCvtHandle *chandle;
ULONG newcamg;
bitmap = (struct MyBitMap *)NewBitMap;
if (dctv4) {
AddMessageNo(MSG_SDCTV4);
}
else {
AddMessageNo(MSG_SDCTV3);
}
if (dctv4) {
Depth = 4;
}
else {
Depth = 3;
}
if (height > 300) {
newcamg = HIRES|LACE;
}
else {
newcamg = HIRES;
}
if (DCTVBase) {
if ((NewBitMap) || (bitmap = MyAllocBitMap(width,height,Depth,FileName))) {
if (ilbm.ParseInfo.iff = AllocIFF()) {
if (chandle = AllocDCTVCvtTags(bitmap,
DCTVCVTA_Type, DCTVCVTT_RGBtoDCTV,
DCTVCVTA_Flags,((newcamg&LACE)?DCTVCVTF_Lace:0)|
DCTVCVTF_Filter|
DCTVCVTF_CustomRGBBuf,
TAG_END)) {
chandle->Red = red;
chandle->Green = green;
chandle->Blue = blue;
// Convert each line
SetMax(chandle->Height);
while (chandle->DstLineNum < chandle->Height) {
i = chandle->SrcLineNum;
SetCur(i);
CvtDCTVLine(chandle);
if (i != chandle->SrcLineNum) {
chandle->Red += width;
chandle->Green += width;
chandle->Blue += width;
}
}
AddMessageNo(MSG_SILBM);
if (!NewBitMap) {
OkFlag = !mysaveilbm(&ilbm, (struct BitMap *)bitmap,newcamg,
width, height, width, height,
(UBYTE (*)[3])(chandle->ColorTable), dctv4?16:8, 4, /* colortable */
mskNone, 0, /* masking, transparent */
NULL, NULL, /* chunklists */
(UBYTE *)FileName,Depth);
}
else {
OkFlag = TRUE;
}
// Free DCTV stuff
FreeDCTVCvt(chandle);
}
else {
strcpy(ErrorMessage,GetMg(MSG_ERR_DCTVBUF));
OkFlag = FALSE;
}
// Close everything down cleanly
FreeIFF(ilbm.ParseInfo.iff);
}
else {
strcpy(ErrorMessage,GetMg(MSG_ERR_IFF));
OkFlag = FALSE;
}
if (!NewBitMap) {
MyFreeBitMap(bitmap,FileName);
}
}
else {
strcpy(ErrorMessage,GetMg(MSG_ERR_ALLOCBIT));
OkFlag = FALSE;
}
}
else {
strcpy(ErrorMessage,GetMg(MSG_ERR_DCTVL));
OkFlag = FALSE;
}
return OkFlag;
}